<p>Each <a href="concepts.html#jobs">Job</a> has a single build plan. When a build of a job is
created, the plan determines what happens.</p><p>A build plan is a sequence of <em>steps</em> to execute. These steps may fetch
down or update <a href="concepts.html#resources">Resources</a>, or execute
<a href="concepts.html#tasks">Tasks</a>.</p><p>A new build of the job is scheduled whenever <a href="get-step.html"><code>get</code></a> steps with
<code>trigger: true</code> have new versions available.</p><p>To visualize the job in the pipeline, resources that appear as <code>get</code>
steps are drawn as inputs, and resources that appear in <code>put</code> steps
appear as outputs.</p><p>A simple unit test job may look something like:</p><div class="highlight"><pre class="verbatim"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">name</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">banana-unit</span><span class="t">
</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">plan</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">banana</span><span class="t">
</span><span class="t">  </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">trigger</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="kc">true</span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">task</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">unit</span><span class="t">
</span><span class="t">  </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">file</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">banana/task.yml</span></pre></div><p>This job says: <a href="get-step.html"><code>get</code></a> the <code>banana</code> resource,
and run a <a href="task-step.html"><code>task</code></a> step called <code>unit</code>, using
the configuration from the <code>task.yml</code> file fetched from the <code>banana</code>
step.</p><p>When new versions of <code>banana</code> are detected, a new build of
<code>banana-unit</code> will be scheduled, because we've set <code>trigger: true</code>.</p><p>Jobs can depend on resources that are produced by or pass through upstream
jobs, by configuring <code>passed: [job-a, job-b]</code> on the
<a href="get-step.html"><code>get</code></a> step.</p><p>Putting these pieces together, if we were to propagate <code>banana</code> from
the above example into an integration suite with another <code>apple</code>
component (pretending we also defined its <code>apple-unit</code> job), the
configuration for the integration job may look something like:</p><div class="highlight"><pre class="verbatim"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">name</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">fruit-basket-integration</span><span class="t">
</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">plan</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">aggregate</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t">  </span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">banana</span><span class="t">
</span><span class="t">    </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">trigger</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="kc">true</span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t">    </span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">passed</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">banana-unit</span><span class="t"></span><span class="pi">]</span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t">  </span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">apple</span><span class="t">
</span><span class="t">    </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">trigger</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="kc">true</span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t">    </span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">passed</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">apple-unit</span><span class="t"></span><span class="pi">]</span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t">  </span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">integration-suite</span><span class="t">
</span><span class="t">    </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">trigger</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="kc">true</span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">task</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">integration</span><span class="t">
</span><span class="t">  </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">file</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">integration-suite/task.yml</span></pre></div><p>Note the use of the <a href="aggregate-step.html"><code>aggregate</code></a> step to
collect multiple inputs at once.</p><p>With this example we've configured a tiny pipeline that will automatically
run unit tests for two components, and continuously run integration tests
against whichever versions pass both unit tests.</p><p>This can be further chained into later "stages" of your pipeline; for
example, you may want to continuously deliver an artifact built from
whichever components pass <code>fruit-basket-integration</code>.</p><p>To push artifacts, you would use a <a href="put-step.html"><code>put</code></a> step
that targets the destination resource. For example:</p><div class="highlight"><pre class="verbatim"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">name</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">deliver-food</span><span class="t">
</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">plan</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">aggregate</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t">  </span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">banana</span><span class="t">
</span><span class="t">    </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">trigger</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="kc">true</span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t">    </span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">passed</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">fruit-basket-integration</span><span class="t"></span><span class="pi">]</span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t">  </span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">apple</span><span class="t">
</span><span class="t">    </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">trigger</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="kc">true</span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t">    </span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">passed</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">fruit-basket-integration</span><span class="t"></span><span class="pi">]</span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t">  </span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">baggy</span><span class="t">
</span><span class="t">    </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">trigger</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="kc">true</span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">task</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">shrink-wrap</span><span class="t">
</span><span class="t">  </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">file</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">baggy/shrink-wrap.yml</span><span class="t">
</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">put</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">bagged-food</span><span class="t">
</span><span class="t">  </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">params</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t">    </span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">bag</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">shrink-wrap/bagged.tgz</span></pre></div><p>This presumes that there's a <code>bagged-food</code>
<a href="concepts.html#resources">resource</a> defined, which understands that the
<code>bag</code> parameter points to a file to ship up to the resource's location.</p><p>Note that both <code>banana</code> and <code>apple</code> list the same job as an
upstream dependency. This guarantees that <code>deliver-food</code> will only
trigger when a version of both of these dependencies pass through the same
build of the integration job (and transitively, their individual unit jobs).
This prevents bad apples or bruised bananas from being delivered. (I'm sorry.)</p>
